using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using System.Runtime.InteropServices;

namespace Raccoom.TreeViewFolderBrowser.DataProviders
{

    /// <summary>
    ///  managed equivalent of IShellFolder interface
    /// </summary>
    [ComImport]
    [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    [Guid("000214E6-0000-0000-C000-000000000046")]
    public interface IShellFolder 
    {
    void ParseDisplayName( 
        IntPtr hwnd,
        IntPtr pbc,    
        String pszDisplayName,
        UInt32 pchEaten,
        out IntPtr ppidl,    
        UInt32 pdwAttributes);    

    void EnumObjects( 
        IntPtr hwnd,
        ESHCONTF grfFlags,
        out IntPtr ppenumIDList);    

    void BindToObject( 
        IntPtr pidl,        
        IntPtr pbc,        
        [In] ref Guid riid,        
        out IntPtr ppv);    

    void BindToStorage( 
        IntPtr pidl,
        IntPtr pbc,    
        [In] ref Guid riid,        
        out IntPtr ppv);    

    [PreserveSig]
        Int32 CompareIDs( 
        Int32 lParam,    
        IntPtr pidl1,    
        IntPtr pidl2);    

    void CreateViewObject( 
        IntPtr hwndOwner,    
        [In] ref Guid riid,        
        out IntPtr ppv);    

    /*      this version is good if cidl is one
* void GetAttributesOf(             UInt32 cidl,
            ref IntPtr apidl,
            ref ESFGAO rgfInOut);
*/ 
    void GetAttributesOf( 
        UInt32 cidl,
        [MarshalAs(UnmanagedType.LPArray, SizeParamIndex=0)]
        IntPtr[] apidl,
        ref ESFGAO rgfInOut);

    void GetUIObjectOf( 
        IntPtr hwndOwner,
        UInt32 cidl,    // number of IntPtr's in incoming array
        [MarshalAs(UnmanagedType.LPArray, SizeParamIndex=1)]
        IntPtr[] apidl,
        [In] ref Guid riid,
        UInt32 rgfReserved,
        out IntPtr ppv);

    /*    this version is good if cidl is one
          void GetUIObjectOf(
          IntPtr hwndOwner,
          UInt32 cidl,
          ref    IntPtr apidl,
          [In] ref Guid riid,
          UInt32 rgfReserved,
          out IntPtr ppv);
       */

    void GetDisplayNameOf(
        IntPtr pidl,
        ESHGDN uFlags,
        out STRRET pName);

    void SetNameOf( 
        IntPtr hwnd,    
        IntPtr pidl,    
        String pszName,    
        ESHCONTF uFlags,    
        out IntPtr ppidlOut);    
    }

    // from ShObjIdl.h
    public enum ESFGAO : uint
    {
    SFGAO_CANCOPY     =  0x00000001,
    SFGAO_CANMOVE     =  0x00000002,
    SFGAO_CANLINK     =  0x00000004,
    SFGAO_LINK        =  0x00010000,
    SFGAO_SHARE       =  0x00020000,
    SFGAO_READONLY    =  0x00040000,
    SFGAO_HIDDEN      =  0x00080000,
    SFGAO_FOLDER      =  0x20000000,
    SFGAO_FILESYSTEM      =  0x40000000,
    SFGAO_HASSUBFOLDER    =  0x80000000,
    }

    public enum ESHCONTF
    {
    SHCONTF_FOLDERS = 0x0020,
    SHCONTF_NONFOLDERS = 0x0040,
    SHCONTF_INCLUDEHIDDEN = 0x0080,
    SHCONTF_INIT_ON_FIRST_NEXT = 0x0100,
    SHCONTF_NETPRINTERSRCH  = 0x0200,
    SHCONTF_SHAREABLE = 0x0400,
    SHCONTF_STORAGE = 0x0800   
    }
      // from shlobj.h
    public enum ESHGDN 
    {
    SHGDN_NORMAL         = 0x0000,
    SHGDN_INFOLDER       = 0x0001,
    SHGDN_FOREDITING     = 0x1000,
    SHGDN_FORADDRESSBAR    = 0x4000,
    SHGDN_FORPARSING     = 0x8000,
    }

    public  enum ESTRRET : int
    {
    eeRRET_WSTR     = 0x0000,            // Use STRRET.pOleStr
    STRRET_OFFSET   = 0x0001,    // Use STRRET.uOffset to Ansi
    STRRET_CSTR     = 0x0002            // Use STRRET.cStr
    }

    /*
    // Microsoft's sample and it works too.
    see sample,    Unions.cs

    union MYUNION2
    {
    int i;
    char str[128];
    };



    [ StructLayout( LayoutKind.Explicit, Size=128 )]
    public struct MyUnion2_1
    {
    [ FieldOffset( 0 )]
    public int i;
    }
    */
    // shlobj.h

    // this works too...from Unions.cs
    [StructLayout(LayoutKind.Explicit, Size=520)]
    public struct STRRETinternal
    {
    [FieldOffset(0)]
    public IntPtr pOleStr;

    [FieldOffset(0)]
    public IntPtr pStr;  // LPSTR pStr;   NOT USED

    [FieldOffset(0)]
    public uint  uOffset;

    }

    [StructLayout(LayoutKind.Sequential )]
    public struct STRRET
    {
    public uint uType;
    public STRRETinternal data;
    }

    public class Guid_IShellFolder 
    {
    public static Guid IID_IShellFolder =
        new Guid("{000214E6-0000-0000-C000-000000000046}");
    }

    /// <summary> Summary description for ExtractIcon.</summary>
    public class ExtractIcon
    {
      [DllImport("shell32.dll", CharSet = CharSet.Auto)]
      private static extern int SHGetFileInfo(
        string pszPath,
        int dwFileAttributes,
        out    SHFILEINFO psfi,
        uint cbfileInfo,
        SHGFI uFlags);

      /// <summary>Maximal Length of unmanaged Windows-Path-strings</summary>
      private const int MAX_PATH = 260;
      /// <summary>Maximal Length of unmanaged Typename</summary>
      private const int MAX_TYPE = 80;

      [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
      private struct SHFILEINFO
      {
        public SHFILEINFO(bool b)
        {
          hIcon = IntPtr.Zero;
          iIcon = 0;
          dwAttributes = 0;
          szDisplayName = "";
          szTypeName = "";
        }
        public IntPtr hIcon;
        public int iIcon;
        public uint dwAttributes;
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = MAX_PATH)]
        public string szDisplayName;
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = MAX_TYPE)]
        public string szTypeName;
      };

      private ExtractIcon()
      {
      }
      [DllImport("User32.dll")]
      private static extern int DestroyIcon(System.IntPtr hIcon);

      [Flags]
      enum SHGFI : int
      {
        /// <summary>get icon</summary>
        Icon = 0x000000100,
        /// <summary>get display name</summary>
        DisplayName = 0x000000200,
        /// <summary>get type name</summary>
        TypeName = 0x000000400,
        /// <summary>get attributes</summary>
        Attributes = 0x000000800,
        /// <summary>get icon location</summary>
        IconLocation = 0x000001000,
        /// <summary>return exe type</summary>
        ExeType = 0x000002000,
        /// <summary>get system icon index</summary>
        SysIconIndex = 0x000004000,
        /// <summary>put a link overlay on icon</summary>
        LinkOverlay = 0x000008000,
        /// <summary>show icon in selected state</summary>
        Selected = 0x000010000,
        /// <summary>get only specified attributes</summary>
        Attr_Specified = 0x000020000,
        /// <summary>get large icon</summary>
        LargeIcon = 0x000000000,
        /// <summary>get small icon</summary>
        SmallIcon = 0x000000001,
        /// <summary>get open icon</summary>
        OpenIcon = 0x000000002,
        /// <summary>get shell size icon</summary>
        ShellIconSize = 0x000000004,
        /// <summary>pszPath is a pidl</summary>
        PIDL = 0x000000008,
        /// <summary>use passed dwFileAttribute</summary>
        UseFileAttributes = 0x000000010,
        /// <summary>apply the appropriate overlays</summary>
        AddOverlays = 0x000000020,
        /// <summary>Get the index of the overlay in the upper 8 bits of the iIcon</summary>
        OverlayIndex = 0x000000040,
      }

      /// <summary>
      /// Get the associated Icon for a file or application, this method always returns
      /// an icon.  If the strPath is invalid or there is no idonc the default icon is returned
      /// </summary>
      /// <param name="strPath">full path to the file</param>
      /// <param name="bSmall">if true, the 16x16 icon is returned otherwise the 32x32</param>
      /// <returns></returns>
      public static Icon GetIcon(string strPath, bool bSmall)
      {
        SHFILEINFO info = new SHFILEINFO(true);
        int cbFileInfo = Marshal.SizeOf(info);
        SHGFI flags;
        if (bSmall)
          flags = SHGFI.Icon | SHGFI.SmallIcon | SHGFI.UseFileAttributes;
        else
          flags = SHGFI.Icon | SHGFI.LargeIcon | SHGFI.UseFileAttributes;

        SHGetFileInfo(strPath, 256, out info, (uint)cbFileInfo, flags);
        return Icon.FromHandle(info.hIcon);
      }
    }

//// deep copy
//    Icon shellIcon = (Icon) System.Drawing.Icon.FromHandle(shinfo.hIcon).Clone();
//    // release handle
//    DestroyIcon(shinfo.hIcon);

}


